#include "vl_c_compile_support.h"
#include "vl_c_config_support.h"
#include "vl_c_dirty_support.h"
#include "vl_c_dep_support.h"

#include "utils/vl_thread_pool.h"
#include "utils/vl_cmd.h"
#include "utils/vl_utils.h"

using namespace VL;

/**
 * @Author: CimZzz
 * @Date: 2022-08-22 13:51:59
 * 
 * 构造函数
 */
CCompileSupport::CCompileSupport(): VLSupport(VLSupport::Aspect::Compile) {

}

/**
 * @Author: CimZzz
 * @Date: 2022-08-19 15:53:54
 * 
 * 执行动作
 * 
 * @param env 环境变量
 */
void CCompileSupport::doAction(VLEnv* env) {
	// 加载 C / C++ 项目工程配置文件, 转换为内存中的数据类型
	this->initProjectMustExist(env);

	auto projectProp = env->projectProperties;
	auto compileParam = env->compileParam;

	if(compileParam->checkDep) {
		// 如果需要检查依赖库
		CDepSupport depSupport;
		env->dependencyParams = std::shared_ptr<DependencyParams>(new DependencyParams);
		env->dependencyParams->depOptions = DependencyParams::DepOptions::DO_CheckOrLoad;
		env->dependencyParams->needPrint = false;
		depSupport.doAction(env);
	}

	// 获取 ConfigBundle
	CConfigSupport configSupport;
	env->configureParams = std::shared_ptr<ConfigureParams>(new ConfigureParams);
	if(compileParam->compileOption != CompileParams::CompileOptions::CO_ALL) {
		if((compileParam->compileOption & CompileParams::CompileOptions::CO_TEST) != 0) {
			// 编译测试项目
			env->configureParams->configOptions |= ConfigureParams::ConfigOptions::CO_CompileTest;
		}
		if((compileParam->compileOption & CompileParams::CompileOptions::CO_EXEC) != 0) {
			// 编译测试项目
			env->configureParams->configOptions |= ConfigureParams::ConfigOptions::CO_CompileExecutable;
		}
		if((compileParam->compileOption & CompileParams::CompileOptions::CO_LIB) != 0) {
			// 编译测试项目
			env->configureParams->configOptions |= ConfigureParams::ConfigOptions::CO_CompileLibrary;
		}
	} else {
		env->configureParams->configOptions = ConfigureParams::ConfigOptions::CO_ALL;
	}
	env->configureParams->needPrint = false;
	configSupport.doAction(env);
	auto configBundle = env->getVariable<CConfigBundle>("C_CONFIG_BUNDLE");

	// 获取 DirtyBundle
	CDirtySupport dirtySupport;
	env->dirtyParams = std::shared_ptr<DirtyParams>(new DirtyParams);
	env->dirtyParams->needPrint = false;
	dirtySupport.doAction(env);
	auto dirtyBundle = env->getVariable<CDirtyBundle>("C_DIRTY_BUNDLE");

	// 进行编译, 先初始化线程池
	env->initThreadPool();
	auto threadPoolPtr = VLThreadPool::getInstance();
	
	// 是否输出详细内容
	auto isVerbose = (env->commonParams->verbose & CommonConfigParams::VerboseType::VT_Compile) != 0;

	/**
	 * ****************************************************************************************
	 * @Author: CimZzz
	 * @Date: 2022-08-22 13:55:59
	 * 代码块说明: 
	 * 
	 * 编译项目中源文件
	 * 
	 */
	
	auto targetFileCollectorPtr = dirtyBundle->targetFileCollectorPtr;
	if(targetFileCollectorPtr.get() != nullptr) {
		ThreadFutureManager manager;
		threadPoolPtr->pendingTask();
		
		// 编译目标文件指令, COMPILER CPPFLAGS CXXFLAGS/CFLAGS SYSROOT SRC_DIR FILE_DIR SOURCE_FILE TARGET_FILE
		const char* compileCommand = "%s %s %s %s -I\"%s\" -I\"%s\" -c \"%s\" -o \"%s\"";
		
		// 编译位置无关目标文件指令, COMPILER CPPFLAGS CXXFLAGS/CFLAGS SYSROOT SRC_DIR FILE_DIR SOURCE_FILE TARGET_FILE
		const char* compileFPICCommand = "%s %s %s %s -I\"%s\" -I\"%s\" -fPIC -c \"%s\" -o \"%s\"";

		for(auto pairIter = targetFileCollectorPtr->begin() ; pairIter != targetFileCollectorPtr->end() ; pairIter ++) {
			// 获取文件对儿
			auto pairPtr = pairIter->second;
			// 获取源文件和目标文件列表
			auto sourceFilePtr = pairPtr->primaryFile;
			auto targetFileListPtr = pairPtr->relateFile;

			// 确保文件夹存在
			auto validFilePtr = sourceFilePtr->getValidFilePtr();
			if(!validFilePtr->getValidFile()->makeSureParentDirExist()) {
				this->throwException("cannot create dir for %s", validFilePtr->getValidFile()->getAbsolutePathStr());
				return;
			}
			for(auto targetIter = targetFileListPtr->begin() ; targetIter != targetFileListPtr->end() ; targetIter ++) {
				auto targetFilePtr = (*targetIter);
				if(!targetFilePtr->getFilePtr()->makeSureParentDirExist()) {
					this->throwException("cannot create dir for %s", targetFilePtr->getAbsolutePathStr());
					return;
				}
				auto validFilePtr = targetFilePtr->getValidFilePtr();
				if(!validFilePtr->getValidFile()->makeSureParentDirExist()) {
					this->throwException("cannot create dir for %s", validFilePtr->getValidFile()->getAbsolutePathStr());
					return;
				}
			}

			auto futurePtr = threadPoolPtr->exec<bool, VLException>([&, sourceFilePtr, targetFileListPtr](const std::shared_ptr<VLFuture>& futurePtr, Buffer* buffer) {
				auto futureCore = FutureBuilder::getCore<bool, VLException>(futurePtr);

				for(auto targetIter = targetFileListPtr->begin() ; targetIter != targetFileListPtr->end() ; targetIter ++) {
					auto targetFilePtr = (*targetIter);
					
					// 编译指令 Formatter
					const char * command;
					// 编译器
					VLFlag COMPILER;
					// 编译参数
					VLFlag COMPILE_FLAGS;
					
					if(targetFilePtr->containFlag(CFileType::CFT_CPP)) {
						COMPILER = configBundle->CXX;
						COMPILE_FLAGS = configBundle->CXXFLAGS;
					} else {
						COMPILER = configBundle->CC;
						COMPILE_FLAGS = configBundle->CFLAGS;
					}

					if(targetFilePtr->containFlag(CFileType::CFT_DYM)) {
						command = compileFPICCommand;
					} else {
						command = compileCommand;
					}


					// 构建编译指令
					buffer->reset();

					buffer->appendPrint(
						command,
						COMPILER.c_str(),
						configBundle->CPPFLAGS.c_str(),
						COMPILE_FLAGS.c_str(),
						configBundle->SYSROOT.c_str(),
						projectProp->srcDir.getAbsolutePathStr(),
						sourceFilePtr->getFilePtr()->getParentPath().c_str(),
						sourceFilePtr->getAbsolutePathStr(),
						targetFilePtr->getAbsolutePathStr()
					);
					buffer->appendByte('\0');

					// 打印编译指令
					std::string cmd(buffer->getBufferAsChar());

					if(isVerbose) {
						_VL_PRINT("%s", cmd.c_str())
					} else {
						_VL_PRINT("compile %s...", targetFilePtr->getAbsolutePathStr())
					}

					if(CMDExecute::execute(cmd)) {
						// 编译失败
						futureCore->setError(this->makeException("compile %s failed", targetFilePtr->getAbsolutePathStr()));
						threadPoolPtr->clearTask();
						return;
					}

					// 编译成功, 保存校验文件
					// s: 源文件时间戳
					// t: 目标文件时间戳
					// cf: CFLAGS / CXXFLAGS
					// c: CXX / CC
					// p: CPPFLAGS
					// sys: SYSROOT
					std::vector<void*> paramList;
					int64_t sourceModifyTime = sourceFilePtr->getModifyTime();
					int64_t targetModifyTime = targetFilePtr->updateModifyTime();
					paramList.push_back(&sourceModifyTime);
					paramList.push_back(&targetModifyTime);
					paramList.push_back(&COMPILE_FLAGS.flagStr);
					paramList.push_back(&COMPILER);
					paramList.push_back(&configBundle->CPPFLAGS.flagStr);
					paramList.push_back(&configBundle->SYSROOT);
					
					// 写入校验属性
					auto validFilePtr = targetFilePtr->getValidFilePtr();
					dirtyBundle->targetValidStreamPtr->write(validFilePtr, paramList);
				}

				if(sourceFilePtr->isFileChange()) {
					// 目标文件编译完成, 源文件也需要进行更新
					// s: 源文件时间戳
					// p: CPPFLAGS
					// h: 头文件时间戳列表
					// 		[header name]: 头文件时间戳

					// 先加载源文件对应的头文件列表
					std::vector<std::shared_ptr<FileWrapper>> headerList;
					if(this->loadSourceHeader(
						sourceFilePtr,
						configBundle->headerFilePool,
						projectProp,
						configBundle,
						buffer,
						headerList
					)) {
						// 加载成功, 更新校验文件
						std::vector<void*> paramList;
						int64_t sourceModifyTime = sourceFilePtr->getModifyTime();
						paramList.push_back(&sourceModifyTime);
						paramList.push_back(&configBundle->CPPFLAGS.flagStr);
						paramList.push_back(&headerList);

						auto validFilePtr = sourceFilePtr->getValidFilePtr();
						dirtyBundle->sourceValidStreamPtr->write(validFilePtr, paramList);
					}

				}

				futureCore->setData(true);
			});

			manager.addFuture(futurePtr);
		}
		threadPoolPtr->continueTask();
		threadPoolPtr->waitForAllTaskDone();
		manager.getOrThrow();
	}

	/**
	 * ****************************************************************************************
	 * @Author: CimZzz
	 * @Date: 2022-08-22 15:36:51
	 * 代码块说明: 
	 * 
	 * 编译项目中测试用例源文件
	 * 
	 */

	auto testTargetFileCollectorPtr = dirtyBundle->testTargetFileCollectorPtr;
	if(testTargetFileCollectorPtr.get() != nullptr) {
		ThreadFutureManager manager;
		threadPoolPtr->pendingTask();
		
		// 编译目标文件指令, COMPILER CPPFLAGS CXXFLAGS/CFLAGS SYSROOT SRC_DIR TEST_SRC FILE_DIR SOURCE_FILE TARGET_FILE
		const char* compileCommand = "%s %s %s %s -I\"%s\" -I\"%s\" -I\"%s\" -c \"%s\" -o \"%s\"";

		for(auto pairIter = testTargetFileCollectorPtr->begin() ; pairIter != testTargetFileCollectorPtr->end() ; pairIter ++) {
			// 获取文件对儿
			auto pairPtr = pairIter->second;
			// 获取源文件和目标文件列表
			auto sourceFilePtr = pairPtr->primaryFile;
			auto targetFileListPtr = pairPtr->relateFile;

			// 确保文件夹存在
			auto validFilePtr = sourceFilePtr->getValidFilePtr();
			if(!validFilePtr->getValidFile()->makeSureParentDirExist()) {
				this->throwException("cannot create dir for %s", validFilePtr->getValidFile()->getAbsolutePathStr());
				return;
			}
			for(auto targetIter = targetFileListPtr->begin() ; targetIter != targetFileListPtr->end() ; targetIter ++) {
				auto targetFilePtr = (*targetIter);
				if(!targetFilePtr->getFilePtr()->makeSureParentDirExist()) {
					this->throwException("cannot create dir for %s", targetFilePtr->getAbsolutePathStr());
					return;
				}
				auto validFilePtr = targetFilePtr->getValidFilePtr();
				if(!validFilePtr->getValidFile()->makeSureParentDirExist()) {
					this->throwException("cannot create dir for %s", validFilePtr->getValidFile()->getAbsolutePathStr());
					return;
				}
			}
			auto futurePtr = threadPoolPtr->exec<bool, VLException>([&, sourceFilePtr, targetFileListPtr](const std::shared_ptr<VLFuture>& futurePtr, Buffer* buffer) {
				auto futureCore = FutureBuilder::getCore<bool, VLException>(futurePtr);
				auto testBundle = sourceFilePtr->getExtraInfo<CTestBundle>();

				for(auto targetIter = targetFileListPtr->begin() ; targetIter != targetFileListPtr->end() ; targetIter ++) {
					auto targetFilePtr = (*targetIter);
					// 编译指令 Formatter
					const char * command = compileCommand;
					// 编译器
					std::string COMPILER;
					
					if(targetFilePtr->containFlag(CFileType::CFT_CPP)) {
						COMPILER = configBundle->CXX;
					} else {
						COMPILER = configBundle->CC;
					}

					// 构建编译指令
					buffer->reset();
					buffer->appendPrint(
						command,
						COMPILER.c_str(),
						testBundle->CPPFLAGS.c_str(),
						testBundle->COMPILE_FLAGS.c_str(),
						configBundle->SYSROOT.c_str(),
						projectProp->srcDir.getAbsolutePathStr(),
						projectProp->testDir.getAbsolutePathStr(),
						sourceFilePtr->getFilePtr()->getParentPath().c_str(),
						sourceFilePtr->getAbsolutePathStr(),
						targetFilePtr->getAbsolutePathStr()
					);
					buffer->appendByte('\0');

					// 打印编译指令
					std::string cmd(buffer->getBufferAsChar());
					if(isVerbose) {
						_VL_PRINT("%s", cmd.c_str())
					} else {
						_VL_PRINT("compile %s...", targetFilePtr->getAbsolutePathStr())
					}

					if(CMDExecute::execute(cmd)) {
						// 编译失败
						futureCore->setError(this->makeException("compile %s failed", targetFilePtr->getAbsolutePathStr()));
						threadPoolPtr->clearTask();
						return;
					}

					// 编译成功, 保存校验文件
					// s: 源文件时间戳
					// t: 目标文件时间戳
					// cf: CFLAGS / CXXFLAGS
					// c: CXX / CC
					// p: CPPFLAGS
					// sys: SYSROOT
					std::vector<void*> paramList;
					int64_t sourceModifyTime = sourceFilePtr->getModifyTime();
					int64_t targetModifyTime = targetFilePtr->updateModifyTime();
					paramList.push_back(&sourceModifyTime);
					paramList.push_back(&targetModifyTime);
					paramList.push_back(&testBundle->COMPILE_FLAGS.flagStr);
					paramList.push_back(&COMPILER);
					paramList.push_back(&testBundle->CPPFLAGS.flagStr);
					paramList.push_back(&configBundle->SYSROOT);
					
					// 写入校验属性
					auto validFilePtr = targetFilePtr->getValidFilePtr();
					dirtyBundle->targetValidStreamPtr->write(validFilePtr, paramList);
				}

				if(sourceFilePtr->isFileChange()) {
					// 目标文件编译完成, 源文件也需要进行更新
					// s: 源文件时间戳
					// p: CPPFLAGS
					// h: 头文件时间戳列表
					// 		[header name]: 头文件时间戳

					// 先加载源文件对应的头文件列表
					std::vector<std::shared_ptr<FileWrapper>> headerList;
					if(this->loadSourceHeader(
						sourceFilePtr,
						configBundle->headerFilePool,
						projectProp,
						configBundle,
						buffer,
						headerList
					)) {
						// 加载成功, 更新校验文件
						std::vector<void*> paramList;
						int64_t sourceModifyTime = sourceFilePtr->getModifyTime();
						paramList.push_back(&sourceModifyTime);
						paramList.push_back(&testBundle->CPPFLAGS.flagStr);
						paramList.push_back(&headerList);

						auto validFilePtr = sourceFilePtr->getValidFilePtr();
						dirtyBundle->sourceValidStreamPtr->write(validFilePtr, paramList);
					}

				}

				futureCore->setData(true);
			});
			manager.addFuture(futurePtr);
		}
		threadPoolPtr->continueTask();
		threadPoolPtr->waitForAllTaskDone();
		manager.getOrThrow();
	}

	/**
	 * ****************************************************************************************
	 * @Author: CimZzz
	 * @Date: 2022-08-22 15:58:42
	 * 代码块说明: 
	 * 
	 * 链接测试用例项目
	 * 
	 */

	auto testBundlesPtr = dirtyBundle->testBundlesPtr;
	if(testBundlesPtr.get() != nullptr) {
		ThreadFutureManager manager;
		threadPoolPtr->pendingTask();
		
		// 链接测试用例指令, COMPILER EXEC_FILE TARGETS LDFLAGS
		const char* compileCommand = "%s -o \"%s\" %s %s";

		for(auto testIter = testBundlesPtr->begin() ; testIter != testBundlesPtr->end() ; testIter ++) {
			auto testBundlePtr = (*testIter);
			auto testFilePtr = testBundlePtr->testFilePtr;
			
			if(!testFilePtr->getFilePtr()->makeSureParentDirExist()) {
				this->throwException("cannot create dir for %s", testFilePtr->getAbsolutePathStr());
			}

			auto validFilePtr = testFilePtr->getValidFilePtr();
			if(!validFilePtr->getValidFile()->makeSureParentDirExist()) {
				this->throwException("cannot create dir for %s", validFilePtr->getValidFile()->getAbsolutePathStr());
			}

			auto futurePtr = threadPoolPtr->exec<bool, VLException>([&, testBundlePtr, testFilePtr](const std::shared_ptr<VLFuture>& futurePtr, Buffer* buffer) {
				auto futureCore = FutureBuilder::getCore<int, VLException>(futurePtr);
				
				std::string COMPILER;
				if(testFilePtr->containFlag(CFileType::CFT_CPP)) {
					COMPILER = configBundle->CXX;
				} else {
					COMPILER = configBundle->CC;
				}

				buffer->reset();
				testFilePtr->composeDependentFiles(buffer);
				buffer->appendByte('\0');
				std::string targets(buffer->getBufferAsChar());

				buffer->reset();
				buffer->appendPrint(
					compileCommand,
					COMPILER.c_str(),
					testFilePtr->getAbsolutePathStr(),
					targets.c_str(),
					testBundlePtr->LDFLAGS.c_str()
				);
				buffer->appendByte('\0');

				std::string cmd(buffer->getBufferAsChar());
				if(isVerbose) {
					_VL_PRINT("%s", cmd.c_str())
				} else {
					_VL_PRINT("link %s...", testFilePtr->getAbsolutePathStr())
				}

				if(CMDExecute::execute(cmd)) {
					// 链接失败
					futureCore->setError(this->makeException("link %s failed", testFilePtr->getAbsolutePathStr()));
					threadPoolPtr->clearTask();
					return;
				}
				// 链接成功, 保存校验文件
				// ldf: LDFLAGS
				// p: 可执行时间戳
				// t: 目标文件时间戳 Map
				// 		[target name]: 目标文件时间戳
				// 		[target name]: 目标文件时间戳
				int64_t modifyTime = testFilePtr->updateModifyTime();
				auto targetFileListPtr = testFilePtr->getDependentFileList();
				std::vector<void*> paramList;
				paramList.push_back(&testBundlePtr->LDFLAGS.flagStr);
				paramList.push_back(&modifyTime);
				paramList.push_back(targetFileListPtr.get());

				auto validFilePtr = testFilePtr->getValidFilePtr();
				dirtyBundle->execStreamPtr->write(validFilePtr, paramList);

				futureCore->setData(true);
			});
			manager.addFuture(futurePtr);
		}

		threadPoolPtr->continueTask();
		threadPoolPtr->waitForAllTaskDone();
		manager.getOrThrow();
	}


	/**
	 * +======================================================================================================================+
	 * @Author: CimZzz
	 * @Date: 2022-11-07 18:09:59
	 * 
	 * 代码分割块，以下内容涉及: 
	 * 
	 * 执行并检查测试用例是否通过
	 * 
	 */
	if(compileParam->checkTest) {
		if(configBundle->checkTestBundlesPtr.get() != nullptr) {
			ThreadFutureManager manager;
			threadPoolPtr->pendingTask();
			for(auto testIter = configBundle->checkTestBundlesPtr->begin() ; testIter != configBundle->checkTestBundlesPtr->end() ; testIter ++) {
				auto testBundlePtr = (*testIter);
				auto testFilePtr = testBundlePtr->testFilePtr;
				auto futurePtr = threadPoolPtr->exec<bool, VLException>([&, testBundlePtr, testFilePtr](const std::shared_ptr<VLFuture>& futurePtr, Buffer* buffer) {
					auto futureCore = FutureBuilder::getCore<int, VLException>(futurePtr);
					std::string testCMD = testFilePtr->getAbsolutePath();
					if(testBundlePtr->passParamsList.get() != nullptr) {
						for(auto paramIter = testBundlePtr->passParamsList->begin() ; paramIter != testBundlePtr->passParamsList->end() ; paramIter ++) {
							testCMD += " " + (*paramIter);
						}
					}
					int ret = CMDExecute::execute(testCMD, isVerbose);
					if(ret) {
						// 链接失败
						futureCore->setError(this->makeException("check test unit \"%s\" return \"%s\", code: %d, path: %s", 
							testBundlePtr->name.c_str(), CMDExecute::getErrorMessage(ret).c_str(), ret, testFilePtr->getAbsolutePathStr()));
						threadPoolPtr->clearTask();
					} else {
						_VL_PRINT_SUCCESS("test unit %s access ...", testBundlePtr->name.c_str())
					}
					futureCore->setData(true);
				});
				manager.addFuture(futurePtr);
			}

			threadPoolPtr->continueTask();
			threadPoolPtr->waitForAllTaskDone();
			manager.getOrThrow();
		}
		
	}

	/**
	 * ****************************************************************************************
	 * @Author: CimZzz
	 * @Date: 2022-08-22 16:56:30
	 * 代码块说明: 
	 * 
	 * 链接可执行项目
	 * 
	 */

	auto execBundlesPtr = dirtyBundle->execBundlesPtr;
	if(execBundlesPtr.get() != nullptr) {
		ThreadFutureManager manager;
		threadPoolPtr->pendingTask();
		
		// 链接可执行项目指令, COMPILER EXEC_FILE TARGETS LDFLAGS
		const char* compileCommand = "%s -o \"%s\" %s %s";

		for(auto execIter = execBundlesPtr->begin() ; execIter != execBundlesPtr->end() ; execIter ++) {
			auto execBundlePtr = (*execIter);
			auto executableFilePtr = execBundlePtr->executableFilePtr;

			if(!executableFilePtr->getFilePtr()->makeSureParentDirExist()) {
				this->throwException("cannot create dir for %s", executableFilePtr->getAbsolutePathStr());
			}

			auto validFilePtr = executableFilePtr->getValidFilePtr();
			if(!validFilePtr->getValidFile()->makeSureParentDirExist()) {
				this->throwException("cannot create dir for %s", validFilePtr->getValidFile()->getAbsolutePathStr());
			}

			auto futurePtr = threadPoolPtr->exec<bool, VLException>([&, execBundlePtr, executableFilePtr](const std::shared_ptr<VLFuture>& futurePtr, Buffer* buffer) {
				auto futureCore = FutureBuilder::getCore<int, VLException>(futurePtr);
				
				std::string COMPILER;
				if(executableFilePtr->containFlag(CFileType::CFT_CPP)) {
					COMPILER = configBundle->CXX;
				} else {
					COMPILER = configBundle->CC;
				}

				buffer->reset();
				executableFilePtr->composeDependentFiles(buffer);
				buffer->appendByte('\0');
				std::string targets(buffer->getBufferAsChar());

				buffer->reset();
				buffer->appendPrint(
					compileCommand,
					COMPILER.c_str(),
					executableFilePtr->getAbsolutePathStr(),
					targets.c_str(),
					execBundlePtr->LDFLAGS.c_str()
				);
				buffer->appendByte('\0');

				std::string cmd(buffer->getBufferAsChar());
				if(isVerbose) {
					_VL_PRINT("%s", cmd.c_str())
				} else {
					_VL_PRINT("link %s...", executableFilePtr->getAbsolutePathStr())
				}

				if(CMDExecute::execute(cmd)) {
					// 链接失败
					futureCore->setError(this->makeException("link %s failed", executableFilePtr->getAbsolutePathStr()));
					threadPoolPtr->clearTask();
					return;
				}
				// 链接成功, 保存校验文件
				// ldf: LDFLAGS
				// p: 可执行时间戳
				// t: 目标文件时间戳 Map
				// 		[target name]: 目标文件时间戳
				// 		[target name]: 目标文件时间戳
				int64_t modifyTime = executableFilePtr->updateModifyTime();
				auto targetFileListPtr = executableFilePtr->getDependentFileList();
				std::vector<void*> paramList;
				paramList.push_back(&execBundlePtr->LDFLAGS.flagStr);
				paramList.push_back(&modifyTime);
				paramList.push_back(targetFileListPtr.get());

				auto validFilePtr = executableFilePtr->getValidFilePtr();
				dirtyBundle->execStreamPtr->write(validFilePtr, paramList);

				futureCore->setData(true);
			});
			manager.addFuture(futurePtr);
		}

		threadPoolPtr->continueTask();
		threadPoolPtr->waitForAllTaskDone();
		manager.getOrThrow();
	}

	/**
	 * ****************************************************************************************
	 * @Author: CimZzz
	 * @Date: 2022-08-22 16:56:20
	 * 代码块说明: 
	 * 
	 * 链接库项目, 以及安装库中头文件
	 * 
	 */

	auto libBundlesPtr = dirtyBundle->libBundlesPtr;
	if(libBundlesPtr.get() != nullptr) {
		ThreadFutureManager manager;
		threadPoolPtr->pendingTask();

		// 链接动态库文件指令 COMPILER DYM TARGETS LDFLAGS
		const char * compileDYMCommand = "%s %s -o \"%s\" %s %s";
		
		// 链接静态库文件指令 STATIC_DIR AR STATIC_FILE_NAME TARGETS
		const char * compileSTATICCommand = "cd \"%s\" && %s rcs \"%s\" %s";

		for(auto libIter = libBundlesPtr->begin() ; libIter != libBundlesPtr->end() ; libIter ++) {
			auto libBundlePtr = (*libIter);
			auto dynamicFilePtr = libBundlePtr->dynamicFilePtr;
			auto staticFilePtr = libBundlePtr->staticFilePtr;
			auto nopStaticFilePtr = libBundlePtr->nopStaticFilePtr;

			if(dynamicFilePtr.get() != nullptr) {
				if(!dynamicFilePtr->getFilePtr()->makeSureParentDirExist()) {
					this->throwException("cannot create dir for %s", dynamicFilePtr->getAbsolutePathStr());
				}

				auto validFilePtr = dynamicFilePtr->getValidFilePtr();
				if(!validFilePtr->getValidFile()->makeSureParentDirExist()) {
					this->throwException("cannot create dir for %s", validFilePtr->getValidFile()->getAbsolutePathStr());
				}
			}

			if(staticFilePtr.get() != nullptr) {
				if(!staticFilePtr->getFilePtr()->makeSureParentDirExist()) {
					this->throwException("cannot create dir for %s", staticFilePtr->getAbsolutePathStr());
				}

				auto validFilePtr = staticFilePtr->getValidFilePtr();
				if(!validFilePtr->getValidFile()->makeSureParentDirExist()) {
					this->throwException("cannot create dir for %s", validFilePtr->getValidFile()->getAbsolutePathStr());
				}
			}

			if(nopStaticFilePtr.get() != nullptr) {
				if(!nopStaticFilePtr->getFilePtr()->makeSureParentDirExist()) {
					this->throwException("cannot create dir for %s", nopStaticFilePtr->getAbsolutePathStr());
				}

				auto validFilePtr = nopStaticFilePtr->getValidFilePtr();
				if(!validFilePtr->getValidFile()->makeSureParentDirExist()) {
					this->throwException("cannot create dir for %s", validFilePtr->getValidFile()->getAbsolutePathStr());
				}
			}

			auto validFilePtr = libBundlePtr->libraryTsFile;
			if(!validFilePtr->getValidFile()->makeSureParentDirExist()) {
				this->throwException("cannot create dir for %s", validFilePtr->getValidFile()->getAbsolutePathStr());
			}


			auto futurePtr = threadPoolPtr->exec<bool, VLException>([&, libBundlePtr, dynamicFilePtr, staticFilePtr](const std::shared_ptr<VLFuture>& futurePtr, Buffer* buffer) {
				auto futureCore = FutureBuilder::getCore<bool, VLException>(futurePtr);
				// 链接可执行文件
				if(dynamicFilePtr.get() != nullptr) {
					if(dynamicFilePtr->isFileChange()) {
						// 动态库文件变化
						std::string COMPILER;
						if(dynamicFilePtr->containFlag(CFileType::CFT_CPP)) {
							COMPILER = configBundle->CXX;
						} else {
							COMPILER = configBundle->CC;
						}

						buffer->reset();
						dynamicFilePtr->composeDependentFiles(buffer);
						buffer->appendByte('\0');
						std::string targets(buffer->getBufferAsChar());

						buffer->reset();
						buffer->appendPrint(
							compileDYMCommand,
							COMPILER.c_str(),
							VL_C_COMPILE_DYM_KEY,
							dynamicFilePtr->getAbsolutePathStr(),
							targets.c_str(),
							libBundlePtr->LDFLAGS.c_str()
						);
						buffer->appendByte('\0');

						std::string cmd(buffer->getBufferAsChar());
						if(isVerbose) {
							_VL_PRINT("%s", cmd.c_str())
						} else {
							_VL_PRINT("link dynamic library %s...", dynamicFilePtr->getAbsolutePathStr())
						}

						if(CMDExecute::execute(cmd)) {
							// 链接失败
							futureCore->setError(this->makeException("link %s failed", dynamicFilePtr->getAbsolutePathStr()));
							threadPoolPtr->clearTask();
							return;
						}

						// 链接成功, 保存校验文件
						// ldf: LDFLAGS
						// l: 库文件时间戳
						// t: 目标文件时间戳 Map
						// 		[target name]: 目标文件时间戳
						// 		[target name]: 目标文件时间戳
						int64_t modifyTime = dynamicFilePtr->updateModifyTime();
						auto targetFileListPtr = dynamicFilePtr->getDependentFileList();
						std::vector<void*> paramList;
						paramList.push_back(&libBundlePtr->LDFLAGS.flagStr);
						paramList.push_back(&modifyTime);
						paramList.push_back(targetFileListPtr.get());

						auto validFilePtr = dynamicFilePtr->getValidFilePtr();
						dirtyBundle->dynamicStreamPtr->write(validFilePtr, paramList);
					}
				}
				// 链接静态文件
				if(staticFilePtr.get() != nullptr) {
					if(staticFilePtr->isFileChange()) {
						// 静态库变化
						VLFile staticDir = staticFilePtr->getFilePtr()->getParent();
						std::string staticName = staticFilePtr->getFilePtr()->getFileName();

						buffer->reset();
						staticFilePtr->composeDependentFiles(buffer);
						buffer->appendByte('\0');
						std::string targets(buffer->getBufferAsChar());

						buffer->reset();
						buffer->appendPrint(
							compileSTATICCommand,
							staticDir.getAbsolutePathStr(),
							configBundle->AR.c_str(),
							staticName.c_str(),
							targets.c_str()
						);
						buffer->appendByte('\0');

						std::string cmd(buffer->getBufferAsChar());
						if(isVerbose) {
							_VL_PRINT("%s", cmd.c_str())
						} else {
							_VL_PRINT("link static library %s...", staticFilePtr->getAbsolutePathStr())
						}


						if(CMDExecute::execute(cmd)) {
							// 链接失败
							futureCore->setError(this->makeException("link %s failed", staticFilePtr->getAbsolutePathStr()));
							threadPoolPtr->clearTask();
							return;
						}

						// 链接成功, 保存校验文件
						// l: 库文件时间戳
						// t: 目标文件时间戳 Map
						// 		[target name]: 目标文件时间戳
						// 		[target name]: 目标文件时间戳
						int64_t modifyTime = staticFilePtr->updateModifyTime();
						auto targetFileListPtr = staticFilePtr->getDependentFileList();
						std::vector<void*> paramList;
						paramList.push_back(&modifyTime);
						paramList.push_back(targetFileListPtr.get());

						auto validFilePtr = staticFilePtr->getValidFilePtr();
						dirtyBundle->staticStreamPtr->write(validFilePtr, paramList);
					}
				}
				// 链接位置无关静态文件
				if(nopStaticFilePtr.get() != nullptr) {
					if(nopStaticFilePtr->isFileChange()) {
						// 静态库变化
						VLFile staticDir = nopStaticFilePtr->getFilePtr()->getParent();
						std::string staticName = nopStaticFilePtr->getFilePtr()->getFileName();


						buffer->reset();
						nopStaticFilePtr->composeDependentFiles(buffer);
						buffer->appendByte('\0');
						std::string targets(buffer->getBufferAsChar());

						buffer->reset();
						buffer->appendPrint(
							compileSTATICCommand,
							staticDir.getAbsolutePathStr(),
							configBundle->AR.c_str(),
							staticName.c_str(),
							targets.c_str()
						);
						buffer->appendByte('\0');

						std::string cmd(buffer->getBufferAsChar());
						if(isVerbose) {
							_VL_PRINT("%s", cmd.c_str())
						} else {
							_VL_PRINT("link NOP static library %s...", nopStaticFilePtr->getAbsolutePathStr())
						}


						if(CMDExecute::execute(cmd)) {
							// 链接失败
							futureCore->setError(this->makeException("link %s failed", nopStaticFilePtr->getAbsolutePathStr()));
							threadPoolPtr->clearTask();
							return;
						}

						// 链接成功, 保存校验文件
						// l: 库文件时间戳
						// t: 目标文件时间戳 Map
						// 		[target name]: 目标文件时间戳
						// 		[target name]: 目标文件时间戳
						int64_t modifyTime = nopStaticFilePtr->updateModifyTime();
						auto targetFileListPtr = nopStaticFilePtr->getDependentFileList();
						std::vector<void*> paramList;
						paramList.push_back(&modifyTime);
						paramList.push_back(targetFileListPtr.get());

						auto validFilePtr = nopStaticFilePtr->getValidFilePtr();
						dirtyBundle->staticStreamPtr->write(validFilePtr, paramList);
					}
				}
				
				// 处理头文件
				auto needRemoveFileListPtr = libBundlePtr->needRemoveFileListPtr;
				if(needRemoveFileListPtr.get() != nullptr) {
					for(auto fileIter = needRemoveFileListPtr->begin() ; fileIter != needRemoveFileListPtr->end() ; fileIter ++) {
						auto filePtr = (*fileIter);
						auto realFilePtr = filePtr->getFilePtr();
						if(realFilePtr->isExist()) {
							_VL_PRINT("delete %s ...\n", realFilePtr->getAbsolutePathStr())
							if(!realFilePtr->deleteFile()) {
								futureCore->setError(this->makeException("delete header file failed: %s", realFilePtr->getAbsolutePathStr()));
								threadPoolPtr->clearTask();
								return;
							}
						}
						
					}
				}

				auto needCopyFileListPtr = libBundlePtr->needCopyFileListPtr;
				if(needCopyFileListPtr.get() != nullptr) {
					for(auto fileIter = needCopyFileListPtr->begin() ; fileIter != needCopyFileListPtr->end() ; fileIter ++) {
						auto filePtr = (*fileIter);
						auto sourceFilePtr = filePtr->getFirstDependentFile();
						if(!filePtr->getFilePtr()->makeSureParentDirExist()) {
							futureCore->setError(this->makeException("create dir for %s failed", filePtr->getAbsolutePathStr()));
							threadPoolPtr->clearTask();
							return;
						}

						_VL_PRINT("copy %s -> %s", sourceFilePtr->getAbsolutePathStr(), filePtr->getAbsolutePathStr())
						if(!sourceFilePtr->getFilePtr()->copy(filePtr->getAbsolutePathStr())) {
							futureCore->setError(this->makeException("copy header file failed: %s -> %s", sourceFilePtr->getAbsolutePathStr(), filePtr->getAbsolutePathStr()));
							threadPoolPtr->clearTask();
							return;
						}
					}
				}

				// 处理成功, 保存库头文件的校验文件
				auto validFilePtr = libBundlePtr->libraryTsFile;
				std::vector<void*> paramList;
				paramList.push_back(&libBundlePtr->headerFileListPtr);
				
				dirtyBundle->headerStreamPtr->write(validFilePtr, paramList);

				futureCore->setData(true);
			});
			manager.addFuture(futurePtr);
		}

		threadPoolPtr->continueTask();
		threadPoolPtr->waitForAllTaskDone();
		manager.getOrThrow();
	}


	/**
	 * ****************************************************************************************
	 * @Author: CimZzz
	 * @Date: 2022-08-23 15:33:08
	 * 代码块说明: 
	 * 
	 * 编译完成执行可执行选项
	 * 
	 */
	auto runProgName = compileParam->runProgName;
	if(!runProgName.empty()) {
		if(configBundle->execBundlesPtr.get() == nullptr) {
			this->throwException("not found program %s, cannot run...", runProgName.c_str());
		}
		for(auto execIter = configBundle->execBundlesPtr->begin() ; execIter != configBundle->execBundlesPtr->end() ; execIter ++) {
			auto execBundlePtr = (*execIter);
			if(execBundlePtr->name == runProgName) {
				_VL_PRINT("run prog: %s ...\n", execBundlePtr->name.c_str())
				// 找到程序, 直接执行
				if(compileParam->runAsRoot) {
					std::string cmd = "sudo " + execBundlePtr->executableFilePtr->getAbsolutePath();
					system(cmd.c_str());
				} else {
					// 找到程序, 直接执行
					system(execBundlePtr->executableFilePtr->getAbsolutePathStr());
				}
				return;
			}
		}
		this->throwException("not found program %s, cannot run...", runProgName.c_str());
 	}

	auto runTestName = compileParam->runTestName;
	if(!runTestName.empty()) {
		if(configBundle->testBundlesPtr.get() == nullptr) {
			this->throwException("not found test unit %s, cannot run...", runTestName.c_str());
		}
		for(auto testIter = configBundle->testBundlesPtr->begin() ; testIter != configBundle->testBundlesPtr->end() ; testIter ++) {
			auto testBundlePtr = (*testIter);
			if(testBundlePtr->name == runTestName) {
				_VL_PRINT("run test unit: %s ...\n", testBundlePtr->name.c_str())
				if(compileParam->runAsRoot) {
					std::string cmd = "sudo " + testBundlePtr->testFilePtr->getAbsolutePath();
					system(cmd.c_str());
				} else {
					// 找到程序, 直接执行
					system(testBundlePtr->testFilePtr->getAbsolutePathStr());
				}
				return;
			}
		}
		this->throwException("not found program %s, cannot run...", runTestName.c_str());
 	}

	if(compileParam->runTestSelect) {
		if(configBundle->testBundlesPtr.get() == nullptr) {
			this->throwException("cannot found any test unit ...");
		}
		VLSelectList selectList;
		selectList.title = "select which test unit to run:";
		for(auto testIter = configBundle->testBundlesPtr->begin() ; testIter != configBundle->testBundlesPtr->end() ; testIter ++) {
			auto testBundlePtr = (*testIter);
			if(testBundlePtr->isCheckItem) {
				// 跳过自检查测试用例
				continue;
			}
			selectList.items.push_back(VLSelectItem {
				.name = testBundlePtr->name,
				.info = testBundlePtr->desc,
				.ptr = testBundlePtr
			});
		}

		// 其他选择项列表
		std::vector<VLSelectItem> items;
		items.push_back(VLSelectItem {
			.name = "r",
			.info = "recompile",
			.ptr = std::shared_ptr<bool>(new bool(true))
		});

		while(true) {
			auto selectResult = VLUtils::select(selectList, items);
			if(selectResult.isNull) {
				break;
			}

			if(selectResult.isOtherItem) {
				// 目前只有一个其他选项, 默认为重编译
				VLEnv newEnv;
				newEnv.commonParams = env->commonParams;
				newEnv.compileParam = env->compileParam;
				newEnv.compileParam->runAsRoot = false;
				newEnv.compileParam->runTestSelect = false;
				// 只编译测试用例
				newEnv.compileParam->compileOption = VL::CompileParams::CO_TEST;
				newEnv.compileParam->runProgName = "";
				newEnv.compileParam->runTestName = "";
				newEnv.projectDir = env->projectDir;

				// 进行编译
				try {
					CCompileSupport::doAction(&newEnv);
					// 编译成功, 刷新选项列表
					auto newConfigBundle = newEnv.getVariable<CConfigBundle>("C_CONFIG_BUNDLE");

					// 先清空当前测试用例
					selectList.items.clear();
					for(auto testIter = newConfigBundle->testBundlesPtr->begin() ; testIter != newConfigBundle->testBundlesPtr->end() ; testIter ++) {
						auto testBundlePtr = (*testIter);
						selectList.items.push_back(VLSelectItem {
							.name = testBundlePtr->name,
							.info = testBundlePtr->desc,
							.ptr = testBundlePtr
						});
					}
				} catch(const VLException& error) {
					// 捕获异常
					_VL_IMPORTANT("recompile error: %s", error.getMessage().c_str())
					bool isContinue = VLUtils::askFor("continue to run other test unit ?", true);
					if(!isContinue) {
						break;
					}
				}
				continue;
			}

			auto testBundlePtr = std::static_pointer_cast<CTestBundle, void>(selectResult.ptr);
			_VL_PRINT("run test unit: %s ...\n", testBundlePtr->name.c_str())
			int resultCode = 0;
			if(compileParam->runAsRoot) {
				std::string cmd = "sudo " + testBundlePtr->testFilePtr->getAbsolutePath();
				resultCode = system(cmd.c_str());
			} else {
				// 找到程序, 直接执行
				resultCode = system(testBundlePtr->testFilePtr->getAbsolutePathStr());
			}

			_VL_PRINT("\n%s stop..... result code: %d \n", testBundlePtr->name.c_str(), resultCode);
			bool isContinue = VLUtils::askFor("continue to run other test unit ?", true);
			if(!isContinue) {
				break;
			}
		}
	}
}


/**
 * @Author: CimZzz
 * @Date: 2022-08-05 19:37:42
 * 
 * 加载源文件中的头文件
 * 
 * @param sourceFile 源文件指针
 * @param headerPool 头文件池指针
 * @param projectPropPtr 项目属性指针
 * @param configBundlePtr 配置数据指针
 * @param buffer 字节缓冲区指针
 * @param headerVector 头文件列表
 * 
 * @return 如果加载成功返回 true
 */
bool CCompileSupport::loadSourceHeader(
	const std::shared_ptr<FileWrapper>& sourceFile,
	std::shared_ptr<FilePool>& headerPool,
	const std::shared_ptr<ProjectProperties>& projectPropPtr,
	const std::shared_ptr<CConfigBundle>& configBundlePtr,
	Buffer* buffer,
	std::vector<std::shared_ptr<FileWrapper>>& headerVector
) {

	VLFlag COMPILER;
	VLFlag COMPILE_FLAGS;
	if(sourceFile->containFlag(CFileType::CFT_C)) {
		// C Source
		COMPILER = configBundlePtr->CC;
		COMPILE_FLAGS = configBundlePtr->CFLAGS;
	} else if(sourceFile->containFlag(CFileType::CFT_CPP)) {
		// CPP Source
		COMPILER = configBundlePtr->CXX;
		COMPILE_FLAGS = configBundlePtr->CXXFLAGS;
	} else {
		#ifdef _VL_BUILD_DEBUG
			_VL_DEBUG("cannot load source header list, because source file type is unknown")
		#endif //_VL_BUILD_DEBUG

		return false;
	}
	if(sourceFile->containFlag(CFileType::CFT_TEST)) {
		// 获取头文件指令 COMPILER CPPFLAGS COMPILE_FLAGS SRC_DIR TEST_DIR FILE_DIR SRC_FILE
		const char * cmdPtr = "%s %s %s -I\"%s\" -I\"%s\" -I\"%s\" -MM \"%s\"";
		
		auto testBundlePtr = sourceFile->getExtraInfo<CTestBundle>();

		buffer->reset();
		buffer->appendPrint(
			cmdPtr,
			COMPILER.c_str(),
			testBundlePtr->CPPFLAGS.c_str(),
			testBundlePtr->COMPILE_FLAGS.c_str(),
			projectPropPtr->srcDir.getAbsolutePathStr(),
			projectPropPtr->testDir.getAbsolutePathStr(),
			sourceFile->getFilePtr()->getParentPath().c_str(),
			sourceFile->getAbsolutePathStr()
		);
		buffer->appendByte('\0');
	} else {
		// 获取头文件指令 COMPILER CPPFLAGS COMPILE_FLAGS SRC_DIR FILE_DIR SRC_FILE
		const char * cmdPtr = "%s %s %s -I\"%s\" -I\"%s\" -MM \"%s\"";

		buffer->reset();
		buffer->appendPrint(
			cmdPtr,
			COMPILER.c_str(),
			configBundlePtr->CPPFLAGS.c_str(),
			COMPILE_FLAGS.c_str(),
			projectPropPtr->srcDir.getAbsolutePathStr(),
			sourceFile->getFilePtr()->getParentPath().c_str(),
			sourceFile->getAbsolutePathStr()
		);
		buffer->appendByte('\0');
	}

	std::string cmd(buffer->getBufferAsChar());
	buffer->reset();
	if(CMDExecute::execute(cmd, buffer, false)) {
		#ifdef _VL_BUILD_DEBUG
			_VL_DEBUG("cannot load source header list failed")
		#endif //_VL_BUILD_DEBUG
		return false;
	}

	// 跳过 .c/.cpp 部分
	buffer->skipUntil(sourceFile->getFilePtr()->getExtName().c_str(), nullptr, Buffer::BufferMatchMode::BMC_Include_EOF | Buffer::BufferMatchMode::BMC_Include_Match);

	Buffer tempBuffer;
	std::shared_ptr<char> linePtr;
	std::shared_ptr<char> headerPtr;
	while((linePtr = buffer->matchString("\\\n", Buffer::BufferMatchMode::BMC_Include_EOF)).get() != nullptr) {
		tempBuffer.reset();
		tempBuffer.appendStrBuffer(linePtr.get());
		if(tempBuffer.getBufferLength() == 0) {
			continue;
		}
		while((headerPtr = tempBuffer.matchString(" ", "\\ ", Buffer::BufferMatchMode::BMC_Include_EOF)).get() != nullptr) {
			std::string headerPath(headerPtr.get());
			headerPath.erase(0, headerPath.find_first_not_of(' '));
			headerPath.erase(headerPath.find_last_not_of(' ') + 1);
			headerPath.erase(headerPath.find_last_not_of('\n') + 1);
			if(headerPath.length() == 0) {
				continue;
			}

			// 从头文件池中获取头文件列表
			auto headerFile = headerPool->fetchFileSync(headerPath, [&]() {
				return std::shared_ptr<FileWrapper>(new FileWrapper(new VLRealPathFile(headerPath)));
			});
			headerVector.push_back(headerFile);
		}
	}

	return true;
}